﻿using Abp.GridFS.Entity;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Abp.GridFS
{
    public class GridFSHelper
    {
        public static GridFsInfo Get(Guid fileId)
        {
            using (GridFSDbContext db = new GridFSDbContext())
            {
                var file = db.GridFsInfo.Where(t => t.Id == fileId).FirstOrDefault();
                return file;
            }
        }

        /// <summary>
        /// 文件下载，并记录日志
        /// </summary>
        /// <param name="fileId"></param>
        /// <param name="currentUsername"></param>
        public static void ResponseOne(Guid fileId, string currentUsername)
        {
            //  大文件直接输出。
            //System.Web.HttpContext.Current.Response.TransmitFile()

            var file = Get(fileId);

            using (GridFSDbContext db = new GridFSDbContext())
            {
                db.DownloadRecord.Add(new DownloadRecord
                {
                    CreateBy = currentUsername,
                    CreateOn = DateTime.Now,
                    GridFsId = fileId,
                    Successful = file != null,
                    Id = 0
                });
                db.SaveChangesAsync();
            }

            if (file == null)
            {
                return;
            }


            string downloadName = System.Web.HttpUtility.UrlEncode(file.FileName);

            System.Web.HttpContext.Current.Response.Clear();
            System.Web.HttpContext.Current.Response.ClearContent();
            System.Web.HttpContext.Current.Response.ClearHeaders();
            System.Web.HttpContext.Current.Response.AddHeader("Content-Length", file.Length.ToString());
            System.Web.HttpContext.Current.Response.ContentType = file.ContentType;//  "application/octet-stream";//
            System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=rdmp_" + downloadName);
            System.Web.HttpContext.Current.Response.OutputStream.Write(file.FileBytes, 0, file.FileBytes.Length);
            System.Web.HttpContext.Current.Response.Flush();//   Flush

            System.Web.HttpContext.Current.Response.End();
        }


        public static void PreviewOne(Guid fileId, string currentUsername)
        {
            //  大文件直接输出。
            //System.Web.HttpContext.Current.Response.TransmitFile()

            var file = Get(fileId);

            using (GridFSDbContext db = new GridFSDbContext())
            {
                db.DownloadRecord.Add(new DownloadRecord
                {
                    CreateBy = currentUsername,
                    CreateOn = DateTime.Now,
                    GridFsId = fileId,
                    Successful = file != null,
                    Id = 0
                });
                db.SaveChangesAsync();
            }

            if (file == null)
            {
                return;
            }


            string downloadName = System.Web.HttpUtility.UrlEncode(file.FileName);

            System.Web.HttpContext.Current.Response.Clear();
            System.Web.HttpContext.Current.Response.ClearContent();
            System.Web.HttpContext.Current.Response.ClearHeaders();
            System.Web.HttpContext.Current.Response.AddHeader("Content-Length", file.Length.ToString());
            System.Web.HttpContext.Current.Response.ContentType = file.ContentType;// "application/octet-stream";//
            System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "inline; filename=rdmp_" + downloadName);
            System.Web.HttpContext.Current.Response.BinaryWrite(file.FileBytes);
            // System.Web.HttpContext.Current.Response.OutputStream.Flush();//   Flush 
            System.Web.HttpContext.Current.Response.End();
        }


        private static byte[] ReadFully(Stream input)
        {
            //input.Position = 0;   //  同下面行,总是归一下零，防止前面已经有用过该流了。
            input.Seek(0, SeekOrigin.Begin);
            using (MemoryStream ms = new MemoryStream())
            {
                input.CopyTo(ms);
                return ms.ToArray();
            }
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="remoteFileName"></param>
        /// <returns></returns>
        public static bool Delete(Guid fileId)
        {
            using (GridFSDbContext db = new GridFSDbContext())
            {
                var f = db.GridFsInfo.Find(fileId);
                db.GridFsInfo.Remove(f);
                db.SaveChanges();
            }
            return true;
        }

        #region upload


        public static Guid Upload(System.Web.HttpPostedFileBase postFile, string createby)
        {
            return Upload(postFile.InputStream, postFile.ContentType, postFile.FileName, createby);
        }

        /// <summary>
        /// 上传文件到gridfs.成功后返回remoteFileName，后期通过该名可以取回文件
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static Guid Upload(System.IO.Stream stream, string contentType, string fileName, string createby)
        {
            string hash = string.Format("{0}_{1}", stream.Length, GetFileHash(stream));

            using (GridFSDbContext db = new GridFSDbContext())
            {
                var tmp = db.GridFsInfo.Where(t => t.Hash == hash).Select(x => x.Id).SingleOrDefault();
                if (tmp != null && tmp != Guid.Empty)
                {
                    return tmp;
                }
            }


            // add
            var id = Guid.NewGuid();
            var gf = new GridFsInfo()
            {
                Hash = hash,
                Id = id,
                FileBytes = ReadFully(stream),
                FileName = fileName,
                CreateOn = DateTime.Now,
                ExtensionName = System.IO.Path.GetExtension(fileName),
                ContentType = contentType,
                CreateBy = createby,
                Length = stream.Length
            };

            using (GridFSDbContext db = new GridFSDbContext())
            {
                db.GridFsInfo.Add(gf);
                db.SaveChanges();
            }
            return id;
        }

        #endregion

        //public static bool ExistHash(string hash)
        //{
        //    using (DataContext db = new DataContext())
        //    {
        //        return db.GridFsInfo.Any(t => t.Hash == hash);
        //    }
        //}

        /// <summary>
        /// 计算文件的哈希值
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        private static string GetFileHash(System.IO.Stream stream)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] byt = md5.ComputeHash(stream);
            string hashcode = BitConverter.ToString(byt);
            hashcode = hashcode.Replace("-", "");
            //stream.Seek(0, SeekOrigin.Begin);// 让流归 0
            return hashcode;
        }
    }
}
